/*
 * 创建日期 2004-9-23
 *
 * 更改所生成文件模板为
 * 窗口 > 首选项 > Java > 代码生成 > 代码和注释
 */
package com.ctsi.commons.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author zhangjw
 * 
 *         更改所生成类型注释的模板为 窗口 > 首选项 > Java > 代码生成 > 代码和注释
 */
public final class UtilObject {

	private static final Logger log = LoggerFactory.getLogger(UtilObject.class);

	/**
	 * 序列化对象,返回ByteBuffer 避免数据复制
	 */
	public static ByteBuffer getByteBuffer(Object obj) {
		ByteOutputStream bos = null;
		ObjectOutputStream oos = null;
		ByteBuffer data = null;
		try {
			bos = new ByteOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(obj);

			data = ByteBuffer.wrap(bos.byteArray(), 0, bos.size());
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			UtilMisc.closeObjNoExc(oos);
			UtilMisc.closeObjNoExc(bos);
		}

		return data;
	}

	/**
	 * 序列化对象
	 */
	public static final byte[] getBytes(Object obj) {
		ByteOutputStream bos = null;
		ObjectOutputStream oos = null;
		byte[] data = null;
		try {
			bos = new ByteOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(obj);
			data = bos.toByteArray();
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			UtilMisc.closeObjNoExc(oos);
			UtilMisc.closeObjNoExc(bos);
		}

		return data;
	}

	/**
	 * 输出对象
	 * 
	 * @param obj
	 * @param out
	 */
	public static final void getBytes(Object obj, OutputStream out) {

		ObjectOutputStream oos = null;
		try {

			oos = new ObjectOutputStream(out);
			oos.writeObject(obj);

		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			UtilMisc.closeObjNoExc(oos);

		}

	}

	/**
	 * 得到序列化对象大小，不支持的返回-1
	 * 
	 * @param obj
	 * @return
	 */
	public static final long getByteCount(Object obj) {
		if (obj == null) {
			return 0;
		}

		if (!(obj instanceof Serializable)) {
			log.warn("{} not instanceof Serializable,return size as -1", obj.getClass().getName());
			return -1;
		}

		OutputStreamByteCount osbc = null;
		ObjectOutputStream oos = null;
		try {
			osbc = new OutputStreamByteCount();
			oos = new ObjectOutputStream(osbc);
			oos.writeObject(obj);
		} catch (IOException e) {
			log.error(e.toString());
			log.warn("error occur,return size as -1 for {}", obj.getClass().getName());
			return -1;
		} finally {
			UtilMisc.closeObjNoExc(oos);
			UtilMisc.closeObjNoExc(osbc);
		}

		return osbc.getByteCount();

	}

	/**
	 * 反序列化
	 * 
	 * @param bytes
	 * @return
	 */
	public static final Object getObject(byte[] bytes) {
		return getObject(bytes, 0, bytes.length);
	}

	public static final Object getObject(byte[] bytes, int offset, int length) {
		ByteArrayInputStream bis = null;
		ObjectInputStream ois = null;
		Object obj = null;

		try {
			bis = new ByteArrayInputStream(bytes, offset, length);
			ois = new ObjectInputStream(bis, Thread.currentThread().getContextClassLoader());
			obj = ois.readObject();
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			UtilMisc.closeObjNoExc(ois);
			UtilMisc.closeObjNoExc(bis);
		}

		return obj;
	}

	public static final Object getObject(InputStream binaryInput) {

		ObjectInputStream ois = null;
		Object obj = null;

		try {

			ois = new ObjectInputStream(binaryInput, Thread.currentThread().getContextClassLoader());
			obj = ois.readObject();
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			UtilMisc.closeObjNoExc(ois);
		}
		return obj;
	}

	public static final boolean equalsHelper(Object o1, Object o2) {
		if (o1 == o2) {
			return true;
		} else if (o1 == null || o2 == null) {
			return false;
		} else {
			return o1.equals(o2);
		}
	}

	public static final int compareToHelper(Comparable o1, Object o2) {
		if (o1 == o2) {
			// handles same-reference, or null
			return 0;
		} else if (o1 == null) {
			return -1;
		} else if (o2 == null) {
			// either o1 or o2 is null, but not both
			return 1;
		} else {
			return o1.compareTo(o2);
		}
	}

	public static final Object getBeanValue(final Object bean,final  String name) {

		try {
			PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), name);
			if (descriptor == null) {
				throw new NoSuchMethodException("Unknown property '" + name + "'");
			}
			Method readMethod = descriptor.getReadMethod();
			if (readMethod == null) {
				throw new NoSuchMethodException("Property '" + name + "' has no getter method");
			}
			setMethodAccessible(readMethod);
			return readMethod.invoke(bean, emptyObjectArray);
		} catch (Exception e) {
			log.error("get fileld " + name + " error, in class " + bean.getClass().getName());
			throw new RuntimeException("get fileld " + name + " error, in class " + bean.getClass().getName());
		}

	}

	public static final String toStr(final Object bean) {
		List<Field> fList = new ArrayList<Field>(12);
		Class<?> bc = bean.getClass();
		getAllFields(bc, fList);
		StringBuilder result = new StringBuilder(512);
		result.append('[');
		result.append('\n');
		result.append(bc.getName());
		for (Field f : fList) {
			final String name = f.getName();
			try {
				if (hasePublicReadMethod(bean, name)) {
					Object value = getBeanValue(bean, name);
					result.append('\n');
					result.append(name);
					result.append('=');

					result.append(value);
				}
			} catch (Exception e) {
				log.error("toStr error", e);
				throw new RuntimeException(e);
			}
		}
		result.append('\n');
		result.append(']');
		return result.toString();
	}

	@SafeVarargs
	public static final <T> boolean contains(final T key, final T... executName) {
		if (UtilValidate.isEmpty(executName))
			return false;
		for (T s : executName) {
			if (equalsHelper(key, s))
				return true;
		}
		return false;
	}

	/**
	 * 按照字段字母排序获取值,不处理executName字段
	 * 
	 * @param bean
	 * @param executName
	 *            不处理的字段
	 * @return
	 */
	public static final String toSortStr(Object bean, String... executName) {
		List<Field> fList = new ArrayList<Field>(12);
		Class<?> bc = bean.getClass();
		getAllFields(bc, fList);
		Collections.sort(fList, new BeanComparator("getName"));
		StringBuilder result = new StringBuilder(512);
		result.append('[');
		result.append('\n');
		result.append(bc.getSimpleName());
		for (Field f : fList) {
			String name = f.getName();
			if (contains(name, executName)) {
				log.trace("skip :{}", name);
				continue;
			}

			try {
				if (hasePublicReadMethod(bean, name)) {
					Object value = getBeanValue(bean, name);
					result.append('\n');
					result.append(name);
					result.append('=');

					result.append(value);
				}
			} catch (Exception e) {
				log.error("toStr error", e);
				throw new RuntimeException(e);
			}
		}
		result.append('\n');
		result.append(']');
		return result.toString();
	}

	public static final boolean hasePublicWriteMethod(Object bean, String fieldName) {
		return hasePublicWriteMethod(bean.getClass(), fieldName);

	}

	public static final boolean hasePublicWriteMethod(Class<?> bean, String fieldName) {
		PropertyDescriptor descriptor = getPropertyDescriptor(bean, fieldName);
		if (descriptor == null) {
			return false;
		}
		Method writeMethod = descriptor.getWriteMethod();
		if (writeMethod == null) {
			return false;
		}
		return Modifier.isPublic(writeMethod.getModifiers());

	}

	public static final boolean hasePublicReadMethod(Object bean, String name) {
		return hasePublicReadMethod(bean.getClass(), name);

	}

	public static final boolean hasePublicReadMethod(Class<?> bean, String name) {
		PropertyDescriptor descriptor = getPropertyDescriptor(bean, name);
		if (descriptor == null) {
			return false;
		}
		Method readMethod = descriptor.getReadMethod();
		if (readMethod == null) {
			return false;
		}
		return Modifier.isPublic(readMethod.getModifiers());

	}

	public static final Field[] getAllPublicReadFields(Class<?> clazz) {
		List<Field> result = new ArrayList<Field>(8);
		try {
			getAllPublicReadFields(clazz, result);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new RuntimeException(e);
		}
		return result.toArray(new Field[0]);

	}

	public static final void getAllFields(Class<?> clazz, List<Field> result) {
		Field[] fa = clazz.getDeclaredFields();
		for (Field f : fa) {
			result.add(f);
		}
		Class<?> suclass = clazz.getSuperclass();
		if (suclass != null) {
			getAllFields(suclass, result);
		}

	}

	public static final Field getFieldByName(Class<?> clazz, String fname) {
		Field field = null;
		try {
			field = clazz.getDeclaredField(fname);
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		} catch (NoSuchFieldException e) {
			field = null;
		}
		if (field == null) {
			Class<?> suclass = clazz.getSuperclass();
			if (suclass != null) {
				return getFieldByName(suclass, fname);
			} else
				return null;
		} else
			return field;

	}

	public static final void getAllPublicReadFields(Class<?> clazz, List<Field> result) {
		Field[] fa = clazz.getDeclaredFields();
		for (Field f : fa) {
			if (hasePublicReadMethod(clazz, f.getName())) {
				result.add(f);
			}

		}
		Class<?> suclass = clazz.getSuperclass();
		if (suclass != null) {
			getAllPublicReadFields(suclass, result);
		}

	}

	/**
	 * 反射调用对象方法
	 * 
	 * @param obj
	 *            调用对象
	 * @param methodName
	 *            方法名称
	 * @param args
	 *            参数，
	 * @return
	 */
	public static final Object runMethod(final Object obj, final String methodName, final Object[] args) {
		assert (methodName != null);
		try {
			Class<?>[] parameterTypes;
			if (args == null) {
				parameterTypes = emptyClassArray;

				return runMethod(obj, methodName, args, parameterTypes);
			}

			else {
				parameterTypes = new Class[args.length];

				boolean paramNull = false;
				for (int i = 0; i < parameterTypes.length; i++) {
					if (args[i] == null) {
						paramNull = true;
						break;
					}
					parameterTypes[i] = args[i].getClass();
				}
				if (paramNull) {
					Method m = getMethodByName(obj.getClass(), methodName, args.length);
					if (m == null) {

						throw new RuntimeException("No or more than one method: " + methodName + "() on object: " + obj.getClass().getName());
					} else {
						return runMethod(m, obj, args);
					}
				} else {
					return runMethod(obj, methodName, args, parameterTypes);
				}
			}

		} catch (SecurityException e) {
			throw new RuntimeException(e);
		}
	}

	private static Method getMethodByName(final Class<?> clazz, final String methodName, final int paramsSize) {
		Method[] ms = clazz.getMethods();
		Method result = null;
		boolean more = false;
		for (Method m : ms) {
			if (m.getName().equals(methodName) && m.getParameterCount() == paramsSize) {
				if (result == null) {
					result = m;
				} else {
					more = true;
					break;
				}

			}
		}
		if (more) {
			log.warn("obj :{} has more than one method {}", clazz, methodName);
			return null;
		}
		return result;
	}

	public static final Object runMethod(final Method method, final Object target, final Object[] args) {
		setMethodAccessible(method);
		try {
			return method.invoke(target, args);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}

	}

	/**
	 * 运行静态方法
	 * 
	 * @param clazz
	 * @param methodName
	 * @param args
	 * @param parameterTypes
	 * @return
	 */
	public static final Object runMethodIfexists(Class<?> clazz, String methodName, Object[] args, Class<?>... parameterTypes) {
		if (haseMethod(clazz, methodName, parameterTypes)) {
			return runMethod(clazz, methodName, args, parameterTypes);
		}else{
			log.info("class {} no method name :{}  with some parameter  ",clazz,methodName);
			return null;	
		}
		
	}

	/**
	 * 反射调用 静态方法,参数中有null，会自动搜索方法，但是不能处理名称一样的方法
	 * 
	 * @param clazz
	 * @param methodName
	 * @param args
	 * @return
	 */
	public static final Object runMethod(Class<?> clazz, String methodName, Object[] args) {
		assert (methodName != null);
		try {
			Class<?>[] parameterTypes;
			if (args == null) {
				parameterTypes = emptyClassArray;

				return runMethod(clazz, methodName, args, parameterTypes);
			}

			else {
				parameterTypes = new Class[args.length];

				boolean paramNull = false;
				for (int i = 0; i < parameterTypes.length; i++) {
					if (args[i] == null) {
						paramNull = true;
						break;
					}
					parameterTypes[i] = args[i].getClass();
				}

				if (paramNull) {
					Method m = getMethodByName(clazz, methodName, args.length);
					if (m == null) {

						throw new RuntimeException("No or more than one method: " + methodName + "() on object: " + clazz.getName());
					} else {
						return runMethod(m, (Object) null, args);
					}
				} else {
					return runMethod(clazz, methodName, args, parameterTypes);
				}

			}

		} catch (SecurityException e) {
			throw new RuntimeException(e);
		}
	}

	/** 一个空的class数组 */
	public static final Class<?>[] emptyClassArray = new Class[0];
	/** 一个空的object数组 */
	public static final Object[] emptyObjectArray = new Object[0];

	public static final Object runMethod(Object obj, String methodName, Object[] args, Class<?>[] parameterTypes) {
		assert (methodName != null);
		try {

			if (parameterTypes == null) {
				parameterTypes = emptyClassArray;
			}
			if (args == null) {
				args = emptyObjectArray;
			}
			Method method = getMatchingAccessibleMethod(obj.getClass(), methodName, parameterTypes);
			if (method == null)
				throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + obj.getClass().getName());

			return method.invoke(obj, args);
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(e);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 运行静态方法
	 * 
	 * @param cls
	 *            需要运行的class
	 * @param methodName
	 *            方法名称
	 * @param args
	 *            方法的的参数
	 * @param parameterTypes
	 *            方法参数类型
	 * @return
	 */
	public static final Object runMethod(Class<?> cls, String methodName, Object[] args, Class<?>[] parameterTypes) {
		assert (methodName != null);
		try {

			if (parameterTypes == null) {
				parameterTypes = emptyClassArray;
			}
			if (args == null) {
				args = emptyObjectArray;
			}
			Method method = getMatchingAccessibleMethod(cls, methodName, parameterTypes);
			if (method == null)
				throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + cls.getName());

			return method.invoke(null, args);
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(e);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * <p>
	 * 找到符合给定名字并有合适参数的可访问的方法 合适的方法是指参数可以从参数列表中分配. 也就是说按给定名字找到的方法可以使用给定的参数
	 * </p>
	 * 
	 * <p>
	 * 该方法遍历所有使用该名字的方法，并调用第一符合要求的方法.
	 * </p>
	 * 
	 * <p>
	 * 该方法被 #runMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)使用.
	 * 
	 * <p>
	 * 如果参数是基本数据类型则它的包装类作为匹配类型处理,比如一个<code>Boolean</code>类 匹配<code>boolean</code>类型的参数
	 * 
	 * @param clazz
	 *            从该类中找到方法
	 * @param methodName
	 *            通过该名字找到方法
	 * @param parameterTypes
	 *            找到方法合适的参数
	 */
	private static final Method getMatchingAccessibleMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) {

		try {
			Method method = clazz.getMethod(methodName, parameterTypes);

			setMethodAccessible(method);
			return method;

		} catch (NoSuchMethodException e) { /* SWALLOW */
		}

		// search through all methods
		final int paramSize = parameterTypes.length;
		Method[] methods = clazz.getMethods();
		for (int i = 0, size = methods.length; i < size; i++) {
			if (methods[i].getName().equals(methodName)) {

				log.trace("Found matching name:{}", methods[i]);

				// compare parameters

				final int methodParamSize = methods[i].getParameterCount();
				if (methodParamSize == paramSize) {
					Class<?>[] methodsParams = methods[i].getParameterTypes();
					boolean match = true;
					for (int n = 0; n < methodParamSize; n++) {
						if (log.isTraceEnabled()) {
							log.trace("Param=" + parameterTypes[n].getName());
							log.trace("Method=" + methodsParams[n].getName());
						}
						if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
							if (log.isTraceEnabled()) {
								log.trace(methodsParams[n] + " is not assignable from " + parameterTypes[n]);
							}
							match = false;
							break;
						}
					}

					if (match) {
						// get accessible version of method
						Method method = getAccessibleMethod(methods[i]);
						if (method != null) {
							if (log.isTraceEnabled()) {
								log.trace(method + " accessible version of " + methods[i]);
							}

							return method;
						}

						log.trace("Couldn't find accessible method.");
					}
				}
			}
		}

		log.info("No match found. for {} name {}", clazz, methodName);
		return null;
	}

	private static void setMethodAccessible(final Method method) {
		try {

            if (!method.isAccessible()) {
                method.setAccessible(true);
            }


		} catch (SecurityException se) {

			log.warn("Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", se);
		}
	}

	/**
	 * <p>
	 * 判定类型是否可以作为调用方法的一个参数，可以正确转换基本数据类型.
	 * </p>
	 * 
	 * <p>
	 * 比如<code>Boolean</code>参数适用于<code>boolean</code>, <code>Long</code>适用于 <code>long</code>, <code>Float</code>适用于<code>float</code>, <code>Integer</code>适用于
	 * <code>int</code>, <code>Double</code> 适用于<code>double</code>. 宽类型转换是允许的但<code>Long</code>不会适合<code>int</code>.
	 * 
	 * @param parameterType
	 *            方法接受的参数类型
	 * @param parameterization
	 *            被检测的参数类型
	 * 
	 * @return 如果分配合适就返回true
	 */
	public static final boolean isAssignmentCompatible(Class<?> parameterType, Class<?> parameterization) {
		// try plain assignment
		if (parameterType.isAssignableFrom(parameterization)) {
			return true;
		}

		if (parameterType.isPrimitive()) {
			Class<?> parameterWrapperClazz = getPrimitiveWrapper(parameterType);
			if (parameterWrapperClazz != null) {
				return parameterWrapperClazz.equals(parameterization);
			}
		}

		return false;
	}

	public static Class<?> getPrimitiveWrapper(Class<?> primitiveType) {
		// does anyone know a better strategy than comparing names?
		if (boolean.class.equals(primitiveType)) {
			return Boolean.class;
		} else if (float.class.equals(primitiveType)) {
			return Float.class;
		} else if (long.class.equals(primitiveType)) {
			return Long.class;
		} else if (int.class.equals(primitiveType)) {
			return Integer.class;
		} else if (short.class.equals(primitiveType)) {
			return Short.class;
		} else if (byte.class.equals(primitiveType)) {
			return Byte.class;
		} else if (double.class.equals(primitiveType)) {
			return Double.class;
		} else if (char.class.equals(primitiveType)) {
			return Character.class;
		} else {

			return null;
		}
	}

	/**
	 * <p>
	 * 返回可使用反射访问的方法，如果没有找到该方法就返回<code>null</code>. 程序会为你封装一个 <code>Class</code>参数类型数组.
	 * </p>
	 * 
	 * @param clazz
	 *            通过该类获取方法
	 * @param methodName
	 *            通过该名字获取方法
	 * @param parameterType
	 *            使用该参数类型
	 */
	public static final Method getAccessibleMethod(Class<?> clazz, String methodName, Class<?> parameterType) {

		Class<?>[] parameterTypes = { parameterType };
		return getAccessibleMethod(clazz, methodName, parameterTypes);

	}

	/**
	 * <p>
	 * 返回可使用反射访问的方法，如果没有找到该方法就返回<code>null</code>. 该方法是{@link #getAccessibleMethod(Method method)}的一个封装.
	 * </p>
	 * 
	 * @param clazz
	 *            通过该类获取方法
	 * @param methodName
	 *            通过该名字获取方法
	 * @param parameterTypes
	 *            使用该参数类型
	 */
	public static final Method getAccessibleMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) {

		return getAccessibleMethod(getMatchingAccessibleMethod(clazz, methodName, parameterTypes));

	}

	/**
	 * <p>
	 * 返回可使用反射访问的方法，如果没有找到该方法就返回<code>null</code>.
	 * </p>
	 * 
	 * @param method
	 *            要调用的方法
	 */
	public static final Method getAccessibleMethod(Method method) {

		if (method == null) {
			return null;
		}

		// If the requested method is not public we cannot call it
		if (!Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// If the declaring class is public, we are done
		Class<?> clazz = method.getDeclaringClass();
		if (Modifier.isPublic(clazz.getModifiers())) {
			return method;
		}

		// Check the implemented interfaces and subinterfaces

		method = getAccessibleMethodFromInterfaceNest(clazz, method.getName(), method.getParameterTypes());
		setMethodAccessible(method);
		return method;

	}

	/**
	 * <p>
	 * 返回可使用反射访问的方法，扫描所有接口子接口，找到特定的方法 如果没有找到该方法就返回<code>null</code>.
	 * </p>
	 * 
	 * <p>
	 * 该方法没有做为私有方法，因为有些类没必要调用更高级别的方法实现.
	 * </p>
	 * 
	 * @param clazz
	 *            接口要检查的父类
	 * @param methodName
	 *            要调用的方法的名称
	 * @param parameterTypes
	 *            参数类型
	 */
	private static final Method getAccessibleMethodFromInterfaceNest(Class<?> clazz, String methodName, Class<?> parameterTypes[]) {

		Method method = null;

		// Search up the superclass chain
		for (; clazz != null; clazz = clazz.getSuperclass()) {

			// Check the implemented interfaces of the parent class
			Class<?> interfaces[] = clazz.getInterfaces();
			for (int i = 0; i < interfaces.length; i++) {

				// Is this interface public?
				if (!Modifier.isPublic(interfaces[i].getModifiers()))
					continue;

				// Does the method exist on this interface?
				try {
					method = interfaces[i].getDeclaredMethod(methodName, parameterTypes);
				} catch (NoSuchMethodException e) {
                }
				if (method != null)
					break;

				// Recursively check our parent interfaces
				method = getAccessibleMethodFromInterfaceNest(interfaces[i], methodName, parameterTypes);
				if (method != null)
					break;

			}

		}

		// If we found a method return it
		if (method != null)
			return (method);

		// We did not find anything
		return (null);

	}

	public static final Method getBeanWriteMethod(Class<?> clazz, String name) throws NoSuchMethodException {
		PropertyDescriptor descriptor = getPropertyDescriptor(clazz, name);
		if (descriptor == null) {
			throw new NoSuchMethodException("class :" + clazz.getName() + "  Unknown property '" + name + "'");
		}
		Method writeMethod = descriptor.getWriteMethod();
		if (writeMethod == null) {
			throw new NoSuchMethodException("Property '" + name + "' has no setter method in " + clazz.getName());
		}

		setMethodAccessible(writeMethod);
		return writeMethod;
	}

	public static final void setBeanValue(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {

		Method writeMethod = getBeanWriteMethod(bean.getClass(), name);
		Object[] values = { value };
		// values[0] = value;
		writeMethod.invoke(bean, values);
	}

	public static final Class<?> getPropertyType(Object bean, String name) {

		PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), name);
		if (descriptor != null) {
			return descriptor.getPropertyType();
		} else {
			return null;
		}

	}

	public static final PropertyDescriptor getPropertyDescriptor(final Class<?> bean,final  String name) {

		if ((bean == null) || (name == null)) {
			log.warn("bean is null");
			return null;
		}
		PropertyDescriptor descriptors[] = getPropertyDescriptorsNoCache(bean);
		if (descriptors == null) {
			return null;
		}
		for (int i = 0; i < descriptors.length; i++) {
			if (name.equals(descriptors[i].getName())) {
				return descriptors[i];
			}
		}
		return null;

	}

	public static final PropertyDescriptor[] getPropertyDescriptorsNoCache(Class<?> bean) {
		BeanInfo beanInfo = null;
		try {
			beanInfo = Introspector.getBeanInfo(bean);
		} catch (IntrospectionException e) {
			return (new PropertyDescriptor[0]);
		}
		PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
		if (descriptors == null) {
			descriptors = new PropertyDescriptor[0];
		}
		return descriptors;
	}

	/**
	 * 对象序列化后base64编码
	 * 
	 * @param obj
	 * @return
	 */
	public static final String ObjectToStr(Serializable obj) {
		if (obj == null)
			return null;

		byte[] en = Base64.base64Encode(UtilObject.getBytes(obj));
		return new String(en);
	}

	/**
	 * base 64编码字符串转化为对象
	 * 
	 * @param str
	 * @return
	 */
	public static final Object StrToObj(String str) {
		if (str == null)
			return null;

		return UtilObject.getObject(Base64.base64Decode(str.getBytes()));
	}

	/**
	 * bean复制数据，注意目前不支持继承的
	 * 
	 * @param source
	 * @param target
	 */
	public static final void CopyBeanToBean(final Object source, final Object target) {

		Method[] method1 = source.getClass().getMethods();

		Method[] method2 = target.getClass().getMethods();

		String methodName1;

		String methodFix1;

		String methodName2;

		String methodFix2;

		for (int i = 0; i < method1.length; i++) {

			methodName1 = method1[i].getName();
			int paramSize = method1[i].getParameterCount();
			boolean get = methodName1.startsWith("get") && paramSize == 0;

			boolean is = methodName1.startsWith("is") && paramSize == 0;
			if (get)
				methodFix1 = methodName1.substring(3, methodName1.length());
			else if (is)
				methodFix1 = methodName1.substring(2, methodName1.length());
			else {
				methodFix1 = null;
			}
			if (get || is) {

				for (int j = 0; j < method2.length; j++) {

					methodName2 = method2[j].getName();

					methodFix2 = methodName2.substring(3, methodName2.length());

					if (methodName2.startsWith("set")) {

						if (methodFix2.equals(methodFix1)) {

							Object[] objs1 = emptyObjectArray;

							Object[] objs2 = new Object[1];

							try {
								setMethodAccessible(method1[i]);
								setMethodAccessible(method2[j]);
								objs2[0] = method1[i].invoke(source, objs1);// 激活obj1的相应的get的方法，objs1数组存放调用该方法的参数,
								method2[j].invoke(target, objs2);// 激活obj2的相应的set的方法，objs2数组存放调用该方法的参数
							} catch (Exception e) {
								log.error("read class {} method {} write class {} method {} ", source.getClass().getName(), methodName1, target.getClass(), methodName2);
								throw new RuntimeException(e);
							}

							break;

						}

					}

				}

			}

		}

	}

	public static boolean haseMethod(Class<?> clazz, final String name, final Class<?>... parameterTypes) {
		Method[] ms = clazz.getMethods();
		final int paramSize;
		if (UtilValidate.isEmpty(parameterTypes)) {
			paramSize = 0;
		} else {
			paramSize = parameterTypes.length;
		}
		for (Method m : ms) {
			if (m.getName().equals(name) && paramSize == m.getParameterCount()) {
				if (paramSize == 0) {
					return true;
				}
				Class<?>[] params1 = m.getParameterTypes();
				boolean found = true;
				for (int i = 0; i < params1.length; i++) {
					if (params1[i] != parameterTypes[i]) {
						found = false;
						break;
					}

				}
				if (found)
					return true;

			}
		}
		return false;

	}

	public static boolean hasePublicMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {
		Method[] ms = clazz.getMethods();
		final int paramSize;
		if (UtilValidate.isEmpty(parameterTypes)) {
			paramSize = 0;
		} else {
			paramSize = parameterTypes.length;
		}

		for (Method m : ms) {
			if (m.getName().equals(name) && paramSize == m.getParameterCount()) {
				if (paramSize == 0) {
					return Modifier.isPublic(m.getModifiers());

				}
				Class<?>[] params1 = m.getParameterTypes();
				boolean found = true;
				for (int i = 0; i < params1.length; i++) {
					if (params1[i] != parameterTypes[i]){
						found = false;
						break;						
					}
					 
				}
				if (found) return Modifier.isPublic(m.getModifiers());

			}
		}
		return false;

	}

	public static final Object runMethod(String methodName, Class<?> clazz, Object... args) {
		return runMethod(clazz, methodName, args);
	}

	public static final Object runMethod(String methodName, Object obj, Object... args) {
		return runMethod(obj, methodName, args);
	}
}
